<?php
namespace api\modules\v1\models;

use api\components\ApiModel;
use common\models\ARAssets;
use common\models\ARBrokerAmount;
use common\models\ARCoinRecord;
use common\models\ARFreezeRecord;
use common\models\ARUser;
use Yii;

/**
 * 资产模型
 * @author CGA
 */
class Assets extends ApiModel
{
    const TRADE_TYPE_NEED = 1;
    const TRADE_TYPE_SUPPLY = 2;

    const CHANGE_INCREASE = 1;
    const CHANGE_REDUCE = 2;

    /**
     * 获取资产安全码
     * @param Object $row 数据记录
     */
    public static function getAssetSecufity($row)
    {
        $salt = Yii::$app->params['salt']['assets'];
        $param = [
            'uid'           => $row->uid,
            'coin'          => $row->coin,
            'amount'        => floatval($row->amount),
            'amount_freeze' => floatval($row->amount_freeze),
            'amount_vouch'  => floatval($row->amount_vouch),
        ];
        $addtime = $row->security_at;
        $code = self::getSecurity($param, $addtime, $salt);
        return $code;
    }

    /**
     * 校验资产安全码
     * @param Object $row 数据记录
     */
    public static function verifyAssetSecufity($row)
    {
        $code = self::getAssetSecufity($row);
        if ($code === $row->security_code) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 校验币余额
     * @param Object $row    数据记录
     * @param number $amount 数额
     */
    public static function verifyCoinAmount($row, $amount)
    {
        $flag = false;
        if (!$row) {
            self::throwError('400003');
        } else {
            $verifyFlag = self::verifyAssetSecufity($row);
            if (!$verifyFlag) {
                self::throwError('400002');
            } else {
                $difference = bcsub($row->amount, $amount, Yii::$app->params['scale']);
                if ($difference >= 0) {
                    $flag = true;
                    return [$flag, $difference];
                } else {
                    self::throwError('400003');
                }
            }
        }
    }

    /**
     * 平台账户变动
     * @param number $type      变动类型
     * @param number $coin      币种
     * @param number $amount    数额
     * @param number $serial_id 流水编号
     */
    public static function platformChangeAmount($type, $coin, $amount, $serial_id = null, $opp_uid = null)
    {
        $platform = ARUser::findOne(['role' => ARUser::ROLE_PLATFORM]);
        $platform_row = ARAssets::findOne(['uid' => $platform->id, 'coin' => $coin]);
        if (!$platform_row) {
            $platform_row = new ARAssets();
            $platform_row->uid = $platform->id;
            $platform_row->coin = $coin;
            $platform_row->amount = 0;
        } else {
            $verifyFlag = self::verifyAssetSecufity($platform_row);
            if (!$verifyFlag) {
                self::throwError('500103');
            }
        }
        if ($type == self::CHANGE_INCREASE) {
            $record_id = ARCoinRecord::addRecord($platform->id, $coin, $amount, $platform_row->amount, 'platform_increase', $serial_id, $opp_uid);
            if (!$record_id) {
                self::throwError('400006');
            }
            $platform_row->amount = bcadd($platform_row->amount, $amount, Yii::$app->params['scale']);
        } elseif ($type == self::CHANGE_REDUCE) {
            $record_id = ARCoinRecord::addRecord($platform->id, $coin, $amount, $platform_row->amount, 'platform_reduce', $serial_id, $opp_uid);
            if (!$record_id) {
                self::throwError('400006');
            }
            $platform_row->amount = bcsub($platform_row->amount, $amount, Yii::$app->params['scale']);
        }
        $platform_row->security_at = Yii::$app->formatter->asTimestamp('now');
        $platform_row->security_code = self::getAssetSecufity($platform_row);
        if (!$platform_row->save()) {
            self::throwError('500104');
        } else {
            $record_flag = ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
            if (!$record_flag) {
                self::throwError('500104');
            }
            return true;
        }
    }

    /**
     * 担保
     * @param number $serial_id 流水编号
     * @param number $uid       用户编号
     * @param number $coin      币种
     * @param number $amount    数额
     */
    public static function vouch($serial_id, $uid, $coin, $amount)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        list($assetFlag, $difference) = self::verifyCoinAmount($row, $amount);
        if ($assetFlag) {
            $brokerAmount = ARBrokerAmount::findOne(['uid' => $uid, 'coin' => $coin]);
            $amount_remain = bcsub($brokerAmount->amount_remain, $amount, Yii::$app->params['scale']);
            if (!$brokerAmount || $amount_remain < 0) {
                self::throwError('400010');
            }
            $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount, $row->amount_vouch, 'vouch_freeze', $serial_id);
            $brokerAmount->amount_remain = $amount_remain;
            $brokerAmount->amount_used = bcadd($brokerAmount->amount_used, $amount, Yii::$app->params['scale']);
            $brokerAmount->num_now = $brokerAmount->num_now + 1;
            if (!$brokerAmount->update()) {
                self::throwError('400011');
            } else {
                ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
                $record_id = ARCoinRecord::addRecord($uid, $coin, $amount, $row->amount, 'vouch', $serial_id);
                $row->amount = bcsub($row->amount, $amount, Yii::$app->params['scale']);
                $row->amount_vouch = bcadd($row->amount_vouch, $amount, Yii::$app->params['scale']);
                $row->security_at = Yii::$app->formatter->asTimestamp('now');
                $row->security_code = self::getAssetSecufity($row);
                if (!$row->update()) {
                    self::throwError('400007');
                }
                ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
                $platform_flag = self::platformChangeAmount(self::CHANGE_INCREASE, $coin, $amount, $serial_id, $uid);
                if ($platform_flag) {
                    return true;
                }
            }
        }
    }

    /**
     * 挂卖
     * @param number $serial_id 流水号
     * @param number $uid       用户编号
     * @param number $coin      币种
     * @param number $amount    数额
     * @param number $fee       手续费
     */
    public static function beSelling($serial_id, $uid, $coin, $amount, $fee = 0)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $amount_total = bcadd($amount, $fee, Yii::$app->params['scale']);
        list($assetFlag, $difference) = self::verifyCoinAmount($row, $amount_total);
        if ($assetFlag) {
            $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount_total, $row->amount_freeze, 'trade_freeze', $serial_id);
            $row->amount_freeze = bcadd($row->amount_freeze, $amount_total, Yii::$app->params['scale']);
            $record_id = ARCoinRecord::addRecord($uid, $coin, $amount, $row->amount, 'trade_freeze');
            if (!$record_id) {
                self::throwError('400006');
            } else {
                $row->amount = bcsub($row->amount, $amount_total, Yii::$app->params['scale']);
                $row->security_at = Yii::$app->formatter->asTimestamp('now');
                $row->security_code = self::getAssetSecufity($row);
                if (!$row->update()) {
                    self::throwError('400007');
                } else {
                    ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
                    ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
                    $userInfo = ARUser::find()->where(['id' => $row->uid])->one();
                    if ($userInfo->role == ARUser::ROLE_AGENT) {
                        $brokerAmount = ARBrokerAmount::find()->where(['uid' => $row->uid, 'coin' => $coin])->one();
                        if ($brokerAmount && bccomp(bcsub($brokerAmount->amount, $row->amount_vouch, Yii::$app->params['scale']), $row->amount, Yii::$app->params['scale'])) {
                            $brokerAmount->amount = bcadd($row->amount_vouch, $row->amount, Yii::$app->params['scale']);
                            $brokerAmount->update();
                        }
                    }
                }
            }
        }
    }

    /**
     * 交易
     * @param number $serial_id 流水号
     * @param number $uid       用户编号
     * @param number $coin      币种
     * @param number $amount    数额
     * @param number $fee       手续费
     */
    public static function trade($serial_id, $uid, $coin, $amount, $fee = 0)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $verifyFlag = self::verifyAssetSecufity($row);
        if (!$verifyFlag) {
            self::throwError('400002');
        }
        $amount_total = bcadd($amount, $fee, Yii::$app->params['scale']);
        $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount_total, $row->amount_freeze, 'trade_payout', $serial_id);
        $row->amount_freeze = bcsub($row->amount_freeze, $amount_total, Yii::$app->params['scale']);
        $row->platform_freezing = bcadd($row->platform_freezing, $amount_total, Yii::$app->params['scale']);
        $row->security_at = Yii::$app->formatter->asTimestamp('now');
        $row->security_code = self::getAssetSecufity($row);
        if (!$row->update()) {
            self::throwError('400007');
        } else {
            $platform_flag = self::platformChangeAmount(self::CHANGE_INCREASE, $coin, $amount_total, $serial_id, $uid);
            if ($platform_flag) {
                ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
                return true;
            }
        }
    }

    /**
     * 交易转账
     * @param number $serial_id 流水编号
     * @param number $type      交易类型
     * @param number $uid       用户编号
     * @param number $opp_uid   对方用户编号
     * @param number $coin      货币类型
     * @param number $amount    交易数额
     * @param number $fee       手续费
     */
    public static function transfer($serial_id, $type, $uid, $opp_uid, $coin, $amount, $fee)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $verifyFlag = self::verifyAssetSecufity($row);
        if (!$verifyFlag) {
            self::throwError('400002');
        }
        if ($type == self::TRADE_TYPE_NEED) {
            $real_amount = $amount;
            $amount_operater = bcadd($amount, $fee, Yii::$app->params['scale']);
        } else {
            $real_amount = bcsub($amount, $fee, Yii::$app->params['scale']);
            $amount_operater = $amount;
        }
        $platform_flag = self::platformChangeAmount(self::CHANGE_REDUCE, $coin, $real_amount, $serial_id, $opp_uid);
        $row->platform_freezing = bcsub($row->platform_freezing, $amount_operater, Yii::$app->params['scale']);
        $row->security_at = Yii::$app->formatter->asTimestamp('now');
        $row->security_code = self::getAssetSecufity($row);
        if (!$row->update()) {
            self::throwError('400007');
        }
        if ($platform_flag) {
            $opp_row = ARAssets::findOne(['uid' => $opp_uid, 'coin' => $coin]);
            $record_id = ARCoinRecord::addRecord($opp_row->uid, $coin, $amount, $opp_row->amount, 'buy');
            if (!$opp_row) {
                $opp_row = new ARAssets();
                $opp_row->uid = $opp_uid;
                $opp_row->coin = $coin;
                $opp_row->amount = 0;
            } else {
                $verifyFlag = self::verifyAssetSecufity($opp_row);
                if (!$verifyFlag) {
                    self::throwError('400003');
                }
                $opp_row->amount = bcadd($opp_row->amount, $real_amount, Yii::$app->params['scale']);
                $opp_row->security_at = Yii::$app->formatter->asTimestamp('now');
                $opp_row->security_code = self::getAssetSecufity($opp_row);
                if (!$opp_row->save()) {
                    self::throwError('400009');
                } else {
                    ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
                    return true;
                }
            }
        }
    }

    /**
     * 担保成功
     * @param number $serial_id 流水编号
     * @param number $uid       用户编号
     * @param number $coin      币种
     * @param number $amount    数额
     */
    public static function assureReturn($serial_id, $uid, $coin, $amount, $isSuccess = 1)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $verifyFlag = self::verifyAssetSecufity($row);
        if (!$verifyFlag) {
            self::throwError('400002');
        }
        $platform_flag = self::platformChangeAmount(self::CHANGE_REDUCE, $coin, $amount, $serial_id, $uid);
        if ($platform_flag) {
            $brokerAmount = ARBrokerAmount::findOne(['uid' => $uid, 'coin' => $coin]);
            $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount, $row->amount_vouch, 'vouch_unfreeze', $serial_id);
            $brokerAmount->amount_remain = bcadd($brokerAmount->amount_remain, $amount, Yii::$app->params['scale']);
            $brokerAmount->amount_used = bcsub($brokerAmount->amount_used, $amount, Yii::$app->params['scale']);
            if ($isSuccess) {
                $brokerAmount->amount_total = bcadd($brokerAmount->amount_total, $amount, Yii::$app->params['scale']);
            }
            if (!$brokerAmount->save()) {
                self::throwError('400011');
            } else {
                ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
                $record_id = ARCoinRecord::addRecord($uid, $coin, $amount, $row->amount, 'vouch_return', $serial_id);
                $row->amount = bcadd($row->amount, $amount, Yii::$app->params['scale']);
                $row->amount_vouch = bcsub($row->amount_vouch, $amount, Yii::$app->params['scale']);
                $row->security_at = Yii::$app->formatter->asTimestamp('now');
                $row->security_code = self::getAssetSecufity($row);
                if (!$row->save()) {
                    self::throwError('400007');
                }
                ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
                return true;
            }
        }
    }

    /**
     * 赔偿
     * @param number $serial_id 订单编号
     * @param number $uid       用户编号
     * @param number $opp_uid   对方用户
     * @param number $coin      币种
     * @param number $amount    数额
     */
    public static function Restitution($serial_id, $uid, $opp_uid, $coin, $amount)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $verifyFlag = self::verifyAssetSecufity($row);
        if (!$verifyFlag) {
            self::throwError('400002');
        }
        $platform_flag = self::platformChangeAmount(self::CHANGE_REDUCE, $coin, $amount, $serial_id, $opp_uid);
        if ($platform_flag) {
            $brokerAmount = ARBrokerAmount::findOne(['uid' => $uid, 'coin' => $coin]);
            $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount, $row->amount_vouch, 'vouch_payout', $serial_id);
            $brokerAmount->amount_remain = bcadd($brokerAmount->amount_remain, $amount, Yii::$app->params['scale']);
            $brokerAmount->amount_used = bcsub($brokerAmount->amount_used, $amount, Yii::$app->params['scale']);
            if (!$brokerAmount->save()) {
                self::throwError('400011');
            } else {
                ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
                $opp_row = ARAssets::findOne(['uid' => $opp_uid, 'coin' => $coin]);
                $record_id = ARCoinRecord::addRecord($opp_row->uid, $coin, $amount, $opp_row->amount, 'restitution');
                if (!$opp_row) {
                    $opp_row = new ARAssets();
                    $opp_row->uid = $opp_uid;
                    $opp_row->coin = $coin;
                    $opp_row->amount = 0;
                } else {
                    $verifyFlag = self::verifyAssetSecufity($opp_row);
                    if (!$verifyFlag) {
                        self::throwError('400003');
                    }
                    $opp_row->amount = bcadd($opp_row->amount, $amount, Yii::$app->params['scale']);
                    $opp_row->security_at = Yii::$app->formatter->asTimestamp('now');
                    $opp_row->security_code = self::getAssetSecufity($opp_row);
                    if (!$opp_row->save()) {
                        self::throwError('400009');
                    } else {
                        ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
                        return true;
                    }
                }
            }
        }
    }

    /**
     * 撤销
     * @param number $serial_id 流水编号
     * @param number $uid       用户编号
     * @param number $coin      币种
     * @param number $amount    数额
     */
    public static function unfreeze($serial_id, $uid, $coin, $amount)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $verifyFlag = self::verifyAssetSecufity($row);
        if (!$verifyFlag) {
            self::throwError('400002');
        }
        $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount, $row->amount_freeze, 'trade_unfreeze', $serial_id);
        $row->amount_freeze = bcsub($row->amount_freeze, $amount, Yii::$app->params['scale']);
        $row->amount = bcadd($row->amount, $amount, Yii::$app->params['scale']);
        $row->security_at = Yii::$app->formatter->asTimestamp('now');
        $row->security_code = self::getAssetSecufity($row);
        if (!$row->update()) {
            self::throwError('400007');
        } else {
            ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
            return true;
        }
    }

    /**
     * 资金返还
     * @param number $serial_id 流水编号
     * @param number $uid       用户编号
     * @param number $coin      币种
     * @param number $amount    数额
     * @param number $isSell    是否挂卖
     * @param number $fee       手续费
     */
    public static function returnBack($serial_id, $uid, $coin, $amount, $isSell, $fee = 0)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        $verifyFlag = self::verifyAssetSecufity($row);
        if (!$verifyFlag) {
            self::throwError('400002');
        }
        $amount_total = $isSell ? bcadd($amount, $fee, Yii::$app->params['scale']) : $amount;
        $platform_flag = self::platformChangeAmount(self::CHANGE_REDUCE, $coin, $amount_total, $serial_id, $uid);
        if ($platform_flag) {
            if ($isSell) {
                $freezerecord_id = ARFreezeRecord::addRecord($uid, $coin, $amount_total, $row->amount_freeze, 'trade_revocation', $serial_id);
                $row->amount_freeze = bcadd($row->amount_freeze, $amount_total, Yii::$app->params['scale']);
                $row->platform_freezing = bcsub($row->platform_freezing, $amount_total, Yii::$app->params['scale']);
                $row->security_at = Yii::$app->formatter->asTimestamp('now');
                $row->security_code = self::getAssetSecufity($row);
                if (!$row->update()) {
                    self::throwError('400007');
                }
                ARFreezeRecord::updateRecord($freezerecord_id, ARFreezeRecord::STATUS_SUCCESS);
                return true;
            } else {
                $record_id = ARCoinRecord::addRecord($uid, $coin, $amount_total, $row->amount, 'trade_unfreeze', $serial_id);
                $row->amount = bcadd($row->amount, $amount_total, Yii::$app->params['scale']);
                $row->platform_freezing = bcsub($row->platform_freezing, $amount_total, Yii::$app->params['scale']);
                $row->security_at = Yii::$app->formatter->asTimestamp('now');
                $row->security_code = self::getAssetSecufity($row);
                if (!$row->update()) {
                    self::throwError('400007');
                }
                ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
                return true;
            }
        }
    }

    /**
     * 入币
     * @param number $uid    用户编号
     * @param number $coin   币种
     * @param number $amount 数额
     */
    public static function into($uid, $coin, $amount)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        if ($row) {
            $verifyFlag = self::verifyAssetSecufity($row);
            if (!$verifyFlag) {
                self::throwError('400002');
            }
        } else {
            $row = new ARAssets();
            $row->uid = $uid;
            $row->coin = $coin;
            $row->amount = 0;
        }
        $record_id = ARCoinRecord::addRecord($uid, $coin, $amount, $row->amount, 'recharge');
        $row->amount = bcadd($row->amount, $amount, Yii::$app->params['scale']);
        $row->security_at = Yii::$app->formatter->asTimestamp('now');
        $row->security_code = self::getAssetSecufity($row);
        if (!$row->save()) {
            self::throwError('400007');
        }
        ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
        return true;
    }

    /**
     * 提款
     * @param number $uid    用户编号
     * @param number $coin   币种
     * @param number $amount 数额
     */
    public static function withdrawals($uid, $coin, $amount)
    {
        $row = ARAssets::findOne(['uid' => $uid, 'coin' => $coin]);
        list($assetFlag, $difference) = self::verifyCoinAmount($row, $amount);
        if ($assetFlag) {
            $record_id = ARCoinRecord::addRecord($uid, $coin, $amount, $row->amount, 'withdraw');
            $row->amount = bcsub($row->amount, $amount, Yii::$app->params['scale']);
            $row->security_at = Yii::$app->formatter->asTimestamp('now');
            $row->security_code = self::getAssetSecufity($row);
            if (!$row->update()) {
                self::throwError('400007');
            }
            ARCoinRecord::updateRecord($record_id, ARCoinRecord::STATUS_SUCCESS);
            $userInfo = ARUser::find()->where(['id' => $row->uid])->one();
            if ($userInfo->role == ARUser::ROLE_AGENT) {
                $brokerAmount = ARBrokerAmount::find()->where(['uid' => $row->uid, 'coin' => $coin])->one();
                if ($brokerAmount && bccomp(bcsub($brokerAmount->amount, $row->amount_vouch, Yii::$app->params['scale']), $row->amount, Yii::$app->params['scale'])) {
                    $brokerAmount->amount = bcadd($row->amount_vouch, $row->amount, Yii::$app->params['scale']);
                    $brokerAmount->update();
                }
            }
            return true;
        }
    }
}
